using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Comdiv.Application;
using Comdiv.Extensions;
using Comdiv.Inversion;
using Comdiv.IO;
using Comdiv.Persistence;

namespace Comdiv.Dbfs{
    public class DbfsRepository : IDbfsRepository{
        private StorageWrapper<IFile> storage;
        public string System { get; set; }
        public DbfsRepository(){
            try{
                storage = myapp.storage.Get<IFile>("dbfs", false);
            }catch(Exception){
                
            }
            System = myapp.files.ReadXml("app.xml?$sys");
            if (System.noContent()) System = "";
            MimeHelper = new MimeHelper();
            
        }

        private static int ids = 0;
        public string NewCode()
        {
            lock (this){
                return (myapp.usrName + "_" + DateTime.Now.ToString("ddMMyyyyhhmmss") + "_" + ids++).Replace("\\", "_");
            }
        }
        private IInversionContainer _container;
        public MimeHelper MimeHelper
        {
            get;
            set;
        }

        public IInversionContainer Container{
            get{
                if (_container.invalid()){
                    lock (this){
                        if (_container.invalid()){
                            Container = ioc.Container;
                        }
                    }
                }
                return _container;
            }
            set { _container = value; }
        }

        public IDbfsRepository Define(string code, string filename, params object[] others){
            if(null==storage) return this;
            lock (this){
                var operation = new FileOperationStructure();
                operation.Code = code;
                operation.Name = Path.GetFileNameWithoutExtension(filename);
                operation.Extension = Path.GetExtension(filename);
                if (operation.Extension.hasContent()){
                    operation.Mime = this.MimeHelper.GetMimeByExtension(operation.Extension);
                }
                if (null != others){
                    foreach (var o in others){
                        if (o is string){
                            operation.Comment = o as string;
                        }
                        else if (o is byte[]){
                            operation.NewData = o as byte[];
                        }
                        else if (o is IDictionary<string, string>){
                            operation.Tags = o as IDictionary<string, string>;
                        }
                        else if (o is IList<string>){
                            var rlist = new List<string>();
                            var wlist = new List<string>();
                            foreach (var r in (o as IList<string>)){
                                if (r.EndsWith("+")){
                                    wlist.Add(r.Substring(0, r.Length - 1));
                                }
                                else{
                                    rlist.Add(r);
                                }
                            }
                            operation.ReadList = rlist.concat(",");
                            operation.ChangeList = wlist.concat(",");
                        }
                    }
                }
                Define(code, operation);
                return this;
            }
        }
        
        public IDbfsRepository Define(string code, IFileOperationStructure operation){
            if (null == storage) return this;
            lock (this){
                if (code.noContent()){
                    code = NewCode();
                }
                LastCode = code;
                if (operation.ReadListApplyMode == ListApplyMode.None){
                    operation.ReadListApplyMode = ListApplyMode.Rewrite;
                }
                if (operation.ChangeListApplyMode == ListApplyMode.None){
                    operation.ChangeListApplyMode = ListApplyMode.Rewrite;
                }
                if (operation.TagApplyMode == ListApplyMode.None){
                    operation.TagApplyMode = ListApplyMode.Merge;
                }
                var file = storage.New();
                file.Code = code;
                file.Name = operation.Name;
                file.Usr = operation.Usr;
                file.System = operation.System;
                if (file.System.noContent()){
                    file.System = this.System;
                }
                if (file.Usr.noContent()) file.Usr = myapp.usrName;
                file.Comment = operation.Comment;
                file.Mime = operation.Mime;
                file.Extension = operation.Extension;
                file.ReadList = operation.ReadList;
                file.ChangeList = operation.ChangeList;
                file.Deleted = operation.Deleted;
                file.NewData = operation.NewData;

                if (operation.Tags != null){
                    using (new TemporaryTransactionSession()){


                        file.Tag = TagHelper.ToString(operation.Tags);

                        if (operation.TagApplyMode == ListApplyMode.Merge){
                            var f = Load(code);

                            if (null != f){
                                file.Tag = TagHelper.ToString(TagHelper.Merge(TagHelper.Parse(f.Tag), operation.Tags));
                            }
                        }
                    }
                }
                using (var s = new TemporaryTransactionSession()){
                    storage.Save(file);
                    s.Commit();
                }
                return this;
            }
        }

        public string LastCode { get; set; }

        public IDbfsRepository Delete(string code){
            if (null == storage) return this;
            lock (this){
                return Define(code, new FileOperationStructure{Deleted = true});
            }

        }

        public IFile Load(string code){
            if (null == storage) return null;
            lock (this){
                var result = storage.Load(code);
                //storage.Refresh(result);
                return result;
            }
        }


        public List<IFile> Search(IDictionary<string,string> tag){
            if (null == storage) return new List<IFile>();
            lock (this){
                return Search("", tag);
            }
        }

        public List<IFile> Search(string name,IDictionary<string,string> tag){
            if (null == storage) return new List<IFile>();
            lock (this){
                return Search(System, name, tag);
            }
        }

        public List<IFile> Search(string system,string name,IDictionary<string,string> tag){
            if (null == storage) return new List<IFile>();
            lock (this){
                return Search(system, name, "", tag);
            }
        }

        public List<IFile> Search(string system,string name,string type,IDictionary<string,string> tag)
        {
            if (null == storage) return new List<IFile>();
            lock (this){
                var hql = "from File this ";
                IList<string> conditions = new List<string>();

                if (name.hasContent()){
                    conditions.Add(" this.Name like '" + name + "' ");
                }
                if (system.hasContent()){
                    conditions.Add(" this.System = '" + system + "' ");
                }
                if (type.hasContent()){
                    conditions.Add(" this.Mime like '" + type + "' ");
                }
                if (null != tag){
                    foreach (var t in tag){
                        if (t.Value.hasContent()){
                            conditions.Add(" TAG:" + t.Key + " like '" + t.Value + "' ");
                        }
                        else{
                            conditions.Add(" ISTAG:" + t.Key + " = 1 ");
                        }
                    }
                }

                if (conditions.Count != 0){
                    var condition = " where " + conditions.concat(" and ");
                    hql += condition;
                }



                return Search(hql);
            }

        }
        public List<IFile> Search(string hql){
            if (null == storage) return new List<IFile>();
            lock (this){
                hql = hql.replace(@"ISTAG:(\w+)", "comdiv.has_tag(this.Tag,'$1')");
                hql = hql.replace(@"TAG:(\w+)", "comdiv.get_tag_value(this.Tag,'$1')");
                return storage.Query(hql).ToList();
            }
        }
    }
}